#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//#define EPS 0.000001
//#define EPS 0.0000001
//#define EPS 0.000000000000001
#define EPS 0.00000000000001
#define MAX_JUMP 0.5
#include "../lbfgs/n.h"
#define M 11

#include "mpi.h"
#include "vectorHistory.h"
#include "scalarHistory.h"
#include "OptimFunc.h"
#include "testFunctions.h"
#include "matrixFunctions.h"
#include "funcProps.h"
#include "minDirected.h"
#include "lbfgsPartial.h"
#include "bfgs.h"
#include "lbfgs.h"

int nprocs;

static struct timeval tm1;

static inline void start()
{
    gettimeofday(&tm1, NULL);
}

static inline void stop()
{
    struct timeval tm2;
    gettimeofday(&tm2, NULL);

    unsigned long long t = 1000 * (tm2.tv_sec - tm1.tv_sec) + (tm2.tv_usec - tm1.tv_usec) / 1000;
    printf("%d %llu\n", N, t);
}

int main(int argc, char**argv)
{
    int mynum;
    int num = 1;
    int tag, next, from;
    
    int masternum;

    double *x = malloc(sizeof(double) * N);
    double *x0 = malloc(sizeof(double) * N);

    int i;

    MPI_Status status;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &mynum);
    MPI_Comm_size(MPI_COMM_WORLD, &nprocs);

    //printf("mynum %d nprocs %d\n", mynum, nprocs);

    tag = 201;

    if (mynum == 0){
        /// master

        start();

        for (i = 1; i < nprocs; ++i) {
            MPI_Send(&num, 1, MPI_INT, i, tag, MPI_COMM_WORLD); 
        }
        for (i = 1; i < nprocs; ++i) {
            MPI_Recv(x, N, MPI_DOUBLE, i, tag, MPI_COMM_WORLD, &status);
            //printf("num %d \n", i);
            //printV("x", x, N);
            //printf("f(x) = %g\n", n17QuarticFunction(x, N));
        }

        stop();

    } else {
        /// slave

        //printV("x0", x0, N);
        //printf("f(x0) = %g\n", n17QuarticFunction(x0, N));

        /// sygnal do startu
        MPI_Recv(&masternum, 1, MPI_INT, 0, tag, MPI_COMM_WORLD, &status);

        for (i=0; i<N; ++i){
            x[i] = 0;
            x0[i] = 1;
        }
	
        x = malloc(sizeof(double) * N);
        lbfgs(n17QuarticFunction, N, x, x0, 20);

        MPI_Send(x, N, MPI_DOUBLE, 0, tag, MPI_COMM_WORLD);  
        //printf("finished %d\n", mynum);      
    }
    
    MPI_Finalize();

    free(x0);
    free(x);

    return 0;
}
